using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;


namespace IronWinter
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {

        TimeSpan updateSpan = TimeSpan.FromMilliseconds(100);
        TimeSpan lastEncode = TimeSpan.MinValue;


        int count = 0;

        #region Constants

        #region enumerations
        enum SessionProperty { GameMode, MapSelection }

        enum GameMode { annihilation, practice }

        enum MapSelection { maplvl1, maplvl2, maplvl3, maplvl4 } //we can do better names, also we need to make some maps anyway. 

        public enum Menu { TitleScreen, MainMenu, CustomMenu, networkMenu, joinNetworkMenu, hostNetworkMenu, SettingsMenu, InGame, PauseMenu, EditMenu, EndGame, hostLobby }

        #endregion


        public const int BAR_SIZE = 200;
        public const int MAP_SIZE = 200;
        public const int SELECTION_SIZE = 475;

        public const int BUTTON_SPACING = 50;

        public const int ACTIVELIMIT = 6;

        public const int MAX_POINTS = 1000;

        public static TimeSpan RES_TICK = TimeSpan.FromSeconds(2); //Can't declare timespans as const apparently
        
        #endregion


        #region Variables

        #region NetworkVariables
        List<AvailableNetworkSession> avalableNetworkSessions;
        NetworkSession networkSession;
        AvailableNetworkSessionCollection availableSessions;



        #endregion


        //Statics 
        public static List<Player> players;
        public static List<Bullet> bullets;
        public static Texture2D genericTexture, lightUnit, mediumUnit, heavyUnit, HQ, building, objective, background, wall;
        public static Map currentMap;

        bool AIMode;
        TimeSpan lastAISpawn;
        bool networkDown = true; // this disables all the stuff

        SpriteFont font;
        Camera camera;
        Cursor mouseCursor;
        MouseState mouseState, mouseStatePrev;
        KeyboardState keyState, keyStatePrev;
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        UnitSpecs AINextUnit;
        Texture2D cursorTexture, buttonTexture, titleScreen, screenBG, logoBar;

        Player currentPlayer, AI;
        int pointsFree;
        

        List<Unit> currentSelection;
        Unit currentEnemySelect;
        Building currentBuildingSelection;
        Boolean invalidUnits;

        Rectangle selectionBox;
        Point selectionCorner;

        List<Unit>[] ctrlGroups;

        List<Objectives> objectives;

        protected Menu menuState;
        List<MenuButton> mainMenuButtons, buildingMenuButtons, abilityMenuButtons, pauseMenuButtons, customMenuButtons, customUnitButtons, editMenuButtons, networkMenuButtons, joinNetworkButtons, settingsMenuButtons, hostLobbyButtons;

        MenuButton currentButton, currentUnitButton, currentUpButton, editUnitButton, editBackButton, messageButton;

        String EndGameMessage;
        

        // TextureLibrary
        AbilityLibrary abilityLibrary;

        int selectedSessionIndex;
        PacketReader packetReader = new PacketReader();
        PacketWriter packetWriter = new PacketWriter();


        #endregion

        #region Initialization

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);

            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// 
        /// </summary>
        protected override void Initialize()
        {

            AIMode = true;
            Components.Add(new GamerServicesComponent(this));

            graphics.IsFullScreen = Properties.Settings.Default.Fullscreen;
            

            invalidUnits = false;
            currentSelection = new List<Unit>();

            // Initalize Alpha game
            players = new List<Player>();
            players.Add(new Player());
            players.Add(new Player());

            int k = 1;
            foreach (Player i in players)
            {
                i.Initialize(k);
                k++;
            }
            currentPlayer = players[0];

            if (AIMode)
                AI = players[1];

            ctrlGroups = new List<Unit>[10];
            for (int i = 0; i < 10; i++)
                ctrlGroups[i] = new List<Unit>();


            mainMenuButtons = new List<MenuButton>();


            joinNetworkButtons = new List<MenuButton>();

            hostLobbyButtons = new List<MenuButton>();

            networkMenuButtons = new List<MenuButton>();

            buildingMenuButtons = new List<MenuButton>();

            abilityMenuButtons = new List<MenuButton>();

            customMenuButtons = new List<MenuButton>();

            customUnitButtons = new List<MenuButton>();

            pauseMenuButtons = new List<MenuButton>();

            editMenuButtons = new List<MenuButton>();

            settingsMenuButtons = new List<MenuButton>();

            objectives = new List<Objectives>();
            bullets = new List<Bullet>();

            menuState = Menu.MainMenu;
            abilityLibrary = new AbilityLibrary();


            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            //This just ends up setting it to the default at the moment
            graphics.PreferredBackBufferWidth = graphics.IsFullScreen ? GraphicsDevice.DisplayMode.Width : Properties.Settings.Default.ResX;
            graphics.PreferredBackBufferHeight = graphics.IsFullScreen ? GraphicsDevice.DisplayMode.Height : Properties.Settings.Default.ResY;
            graphics.ApplyChanges();
    
            lightUnit = Content.Load<Texture2D>(@"textures\Light");
            mediumUnit = Content.Load<Texture2D>(@"textures\Medium");
            heavyUnit = Content.Load<Texture2D>(@"textures\Heavy");
            HQ = Content.Load<Texture2D>(@"textures\HQ");
            building = Content.Load<Texture2D>(@"textures\Building");
            objective = Content.Load<Texture2D>(@"textures\Objective");
            background = Content.Load<Texture2D>(@"textures\background1");

            camera = new Camera(graphics.GraphicsDevice.Viewport);

            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            titleScreen = Content.Load<Texture2D>(@"textures\TitleScreen");
            screenBG = Content.Load<Texture2D>(@"textures\ScreenBG");
            cursorTexture = Content.Load<Texture2D>(@"textures\mouse-cursor-icon");
            logoBar = Content.Load<Texture2D>(@"textures\LogoBar");
            wall = Content.Load<Texture2D>(@"textures\Wall");


            //Temp, obviously
            for (int i = 0; i < 4; i++)
            {
                Ability.AbilityList.Add(new Ability("Temp Ability"));
            }

            //Load ability and equipment textures
            for (int i = 0; i < Ability.AbilityList.Count; i++)
                Ability.AbilityList[i].SetTex(Content.Load<Texture2D>(@"textures\Ability" + i));

            Texture2D[] weapTex = new Texture2D[EquipmentLibrary.WEAPON_COUNT];
            Texture2D[] arTex = new Texture2D[EquipmentLibrary.ARMOR_COUNT];
            Texture2D[] itemTex = new Texture2D[EquipmentLibrary.ITEM_COUNT];

            for (int i = 0; i < weapTex.Length; i++)
                weapTex[i] = Content.Load<Texture2D>(@"textures\Weapon" + i);

            for (int i = 0; i < arTex.Length; i++)
                arTex[i] = Content.Load<Texture2D>(@"textures\Armor" + i);

            for (int i = 0; i < itemTex.Length; i++)
                itemTex[i] = Content.Load<Texture2D>(@"textures\Item" + i);

            EquipmentLibrary.LoadContent(weapTex, arTex, itemTex);

            for (int i = 0; i < Unit.Portraits.Length; i++)
                Unit.Portraits[i] = Content.Load<Texture2D>(@"textures\Portrait" + i);

            loadUnitSet();

            genericTexture = new Texture2D(GraphicsDevice, 1, 1);
            genericTexture.SetData(new Color[] { Color.White });

            mouseCursor = new Cursor(cursorTexture);

            Bullet.bulletTextures = new Texture2D[1];//probably only need one unless someone wants to do some spriting
            Bullet.bulletTextures[0] = Content.Load<Texture2D>(@"textures\Bullet");

            font = Content.Load<SpriteFont>(@"Fonts\Miramonte");
            MenuButton.menuFont = font;

            buttonTexture = Content.Load<Texture2D>(@"textures\Button");

            //Create all of the buttons
            Vector2 center = new Vector2(GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2);


            //Main menu
            mainMenuButtons.Add(new MenuButton("Play", MenuButton.ButtonAction.Play, new Vector2(center.X - 125, center.Y - 100), buttonTexture));
            mainMenuButtons.Add(new MenuButton("Customize Units", MenuButton.ButtonAction.CustomMenu, new Vector2(center.X - 125, center.Y), buttonTexture));
            mainMenuButtons.Add(new MenuButton("Settings/Credits", MenuButton.ButtonAction.SettingsMenu, new Vector2(center.X - 125, center.Y + 100), buttonTexture));
            mainMenuButtons.Add(new MenuButton("Network Play Unavailable", MenuButton.ButtonAction.MainMenu, new Vector2(center.X - 125, center.Y + 200), buttonTexture));
            mainMenuButtons.Add(new MenuButton("Quit", MenuButton.ButtonAction.Quit, new Vector2(center.X - 125, center.Y + 300), buttonTexture));

            //NetworkMenu
            networkMenuButtons.Add(new MenuButton("Back", MenuButton.ButtonAction.MainMenu, new Vector2(center.X - 125, center.Y - 100), buttonTexture));
            networkMenuButtons.Add(new MenuButton("Host Network Game", MenuButton.ButtonAction.HostGame, new Vector2(center.X - 125, center.Y), buttonTexture));
            networkMenuButtons.Add(new MenuButton("Join Network Game", MenuButton.ButtonAction.FindGame, new Vector2(center.X - 125, center.Y + 100), buttonTexture));
            
            //waiting to Start Session Menu
            hostLobbyButtons.Add(new MenuButton("Quit", MenuButton.ButtonAction.MainMenu, new Vector2(center.X - 125, center.Y), buttonTexture));
            hostLobbyButtons.Add(new MenuButton("StartGame", MenuButton.ButtonAction.InitializeNetworkGame, new Vector2(center.X - 125, center.Y - 100), buttonTexture));
           
            //join network Menu
            //String is null on purpose.
            //and yes, converting null to a string has a purpose
            joinNetworkButtons.Add(new MenuButton((string)null, MenuButton.ButtonAction.joingame0, new Vector2(center.X - 125, center.Y), buttonTexture));
            joinNetworkButtons.Add(new MenuButton((string)null, MenuButton.ButtonAction.joingame1, new Vector2(center.X - 125, center.Y + 100), buttonTexture));
            joinNetworkButtons.Add(new MenuButton((string)null, MenuButton.ButtonAction.joingame2, new Vector2(center.X - 125, center.Y + 200), buttonTexture));
            joinNetworkButtons.Add(new MenuButton("Quit", MenuButton.ButtonAction.MainMenu, new Vector2(center.X - 125, 200), buttonTexture));

            //Settings
            settingsMenuButtons.Add(new MenuButton("Toggle Fullscreen", MenuButton.ButtonAction.FullScreen, new Vector2(center.X - 125, center.Y), buttonTexture));
            settingsMenuButtons.Add(new MenuButton("Back", MenuButton.ButtonAction.MainMenu, new Vector2(center.X - 125, center.Y + 100), buttonTexture));
            
            //Customization menu
            int customMenuStart = 200;

            customMenuButtons.Add(new MenuButton("Activate Unit", MenuButton.ButtonAction.ActivateUnit, new Vector2(100, customMenuStart), buttonTexture));
            //customMenuButtons.Add(new MenuButton("Add Unit", MenuButton.ButtonAction.AddUnit, new Vector2(100, customMenuStart + (MenuButton.height + BUTTON_SPACING)), buttonTexture));
            //customMenuButtons.Add(new MenuButton("Duplicate Unit", MenuButton.ButtonAction.DupUnit, new Vector2(100, customMenuStart + (MenuButton.height + BUTTON_SPACING) * 2), buttonTexture));
            customMenuButtons.Add(new MenuButton("Edit Unit", MenuButton.ButtonAction.EditUnit, new Vector2(100, customMenuStart + (MenuButton.height + BUTTON_SPACING)), buttonTexture));
            //customMenuButtons.Add(new MenuButton("Remove Unit", MenuButton.ButtonAction.RemUnit, new Vector2(100, customMenuStart + (MenuButton.height + BUTTON_SPACING) * 4), buttonTexture));
            customMenuButtons.Add(new MenuButton("Back", MenuButton.ButtonAction.MainMenu, new Vector2(100, customMenuStart + (MenuButton.height + BUTTON_SPACING) * 2), buttonTexture));

            //Pause menu
            pauseMenuButtons.Add(new MenuButton("Quit", MenuButton.ButtonAction.MainMenu, new Vector2(center.X - 125, 200), buttonTexture));
            pauseMenuButtons.Add(new MenuButton("Return to Game", MenuButton.ButtonAction.Play, new Vector2(center.X - 125, 300), buttonTexture));

            //Message Menu

            messageButton = (new MenuButton("Message Button, i take you to the main menu", MenuButton.ButtonAction.MainMenu, new Vector2(center.X - 125, center.Y - 100), buttonTexture));

            //Edit menu

            if(!networkDown)
                for (int i = 0; i < Ability.AbilityList.Count; i++)
                    editMenuButtons.Add(new MenuButton(new Vector2(100 + i * Ability.DISPLAY_SIZE * 1.5f, 150 + MenuButton.cheight), Ability.AbilityList[i].texture,
                        Weapon.types.none, Armor.types.none, Item.types.none, i));

            for (int i = 0; i < EquipmentLibrary.WEAPON_COUNT; i++)
                editMenuButtons.Add(new MenuButton(new Vector2(100 + i * Ability.DISPLAY_SIZE * 1.5f, 150 + MenuButton.cheight + Ability.DISPLAY_SIZE * 1.5f),
                    EquipmentLibrary.getWeapon(i).texture, (Weapon.types)i, Armor.types.none, Item.types.none, -1));

            for (int i = 0; i < EquipmentLibrary.ARMOR_COUNT; i++)
                editMenuButtons.Add(new MenuButton(new Vector2(100 + i * Ability.DISPLAY_SIZE * 1.5f, 150 + MenuButton.cheight + Ability.DISPLAY_SIZE * 1.5f * 2),
                    EquipmentLibrary.getArmor(i).texture, Weapon.types.none, (Armor.types)i, Item.types.none, -1));

            for (int i = 0; i < EquipmentLibrary.ITEM_COUNT; i++)
                editMenuButtons.Add(new MenuButton(new Vector2(100 + i * Ability.DISPLAY_SIZE * 1.5f, 150 + MenuButton.cheight + Ability.DISPLAY_SIZE * 1.5f * 3),
                    EquipmentLibrary.getItem(i).texture, Weapon.types.none, Armor.types.none, (Item.types)i, -1));

            editBackButton = new MenuButton("Back", MenuButton.ButtonAction.CustomMenu, new Vector2(100, GraphicsDevice.Viewport.Bounds.Bottom - MenuButton.height - 100), buttonTexture);

            currentMap = new Map("Level1.iwmap");
            
            currentMap.initalize(); //for testing
            //End map Test
            currentButton = mainMenuButtons[0];

            mouseCursor = new Cursor(cursorTexture);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        #endregion

        #region network

        #region listnerHandlerClasses

        IAsyncResult asyncResult;


        #endregion

        // add Players into fileWriter
        public void writeNetworkData()
        {
        }


        // read Players from filereader
        public void readNetworkData()
        {
        }


        private void initializeHostGame()
        {
            //TODO NOW // MAY implement
            NetworkSessionProperties sessionProperties = new NetworkSessionProperties();

            sessionProperties[(int)SessionProperty.GameMode] = (int)GameMode.annihilation;

            sessionProperties[(int)SessionProperty.MapSelection] = (int)MapSelection.maplvl1;

            try
            {
                asyncResult = NetworkSession.BeginCreate(NetworkSessionType.SystemLink, 1, 8, 2, sessionProperties, null, null);
                menuState = Menu.hostLobby;


                // Activate the network busy screen, which will display
                // an animation until this operation has completed.

            }
            catch (Exception exception)
            {
                //ErrorMessage man!
            }
        }

        private void SessionCreated()
        {

            networkSession = NetworkSession.EndCreate(asyncResult);
            asyncResult = null;
            networkSession.AllowJoinInProgress = true;
            networkSession.AllowHostMigration = false;
            menuState = Menu.hostLobby;
        }

        private void InitializeNetworkGame()
        {
            networkSession.StartGame();
            menuState = Menu.InGame;
        }

        private void joinNetworkGame(int index)
        {
       
            currentPlayer = players[1]; // you are now player 2
            currentPlayer.unitSpecs = players[0].unitSpecs;
            networkSession = NetworkSession.Join(availableSessions[index]);
            menuState = Menu.hostLobby;
            currentPlayer.id = 2;

            initGame();

            networkSession.Update();
        }

        public void initalizeProfile()
        {
            // Dont need it?
        }

        // TODO


        #endregion

        #region Update
        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        /// 
        // event Handlers


        protected override void Update(GameTime gameTime)
        {
            //if (!IsActive) //mysteriously once gfwl comes up this is never true again...
             //   return;
            
            mouseState = Mouse.GetState();
            keyState = Keyboard.GetState();

            switch (menuState)
            {
                case Menu.MainMenu:
                    UpdateMenu(mainMenuButtons);
                    break;
                case Menu.CustomMenu:
                    UpdateMenu(customMenuButtons);
                    break;
                case Menu.EditMenu:
                    UpdateEditMenu();
                    break;
                case Menu.SettingsMenu:
                    UpdateMenu(settingsMenuButtons);
                    break;
                case Menu.InGame:
                    UpdateGame(gameTime);
                    break;
                case Menu.PauseMenu:
                    UpdateMenu(pauseMenuButtons);
                    break;
                case Menu.EndGame:
                    UpdateMenu(pauseMenuButtons);
                    break;
                case Menu.networkMenu: 
                    UpdateMenu(networkMenuButtons);
                    break;
                case Menu.joinNetworkMenu:
                    UpdateMenu(joinNetworkButtons);
                    break;
                case Menu.hostNetworkMenu:
                    Console.WriteLine("Error"); //We not doing anything with this quite yet
                    break;
                case Menu.hostLobby:
                    UpdateHostLobby();
                    UpdateMenu(hostLobbyButtons);
                    break;
                default:
                    Console.WriteLine("Error");
                    break;
            }

            mouseStatePrev = mouseState;
            keyStatePrev = keyState;

            base.Update(gameTime);
        }

        protected void UpdateHostLobby()
        {
            if (networkSession != null)
            {
                networkSession.Update();
                if (networkSession.IsHost)
                {
                    //chill
                }
                else
                    if (networkSession.SessionState == NetworkSessionState.Playing)
                    {
                        menuState = Menu.InGame;
                    }

            }

            else if ((asyncResult != null) && asyncResult.IsCompleted)
            {
                SessionCreated();
            }



        }


        protected void UpdateEditMenu()
        {
            bool umouseIn, mouseIn;
            umouseIn = mouseIn = false;
            MenuButton mouseInButton = null;
            foreach (MenuButton mb in editMenuButtons)
            {
                if (mb.bounds.Contains(mouseState.X, mouseState.Y))
                {
                    umouseIn = true;
                    mouseInButton = mb;
                }
            }

            if (editBackButton.bounds.Contains(mouseState.X, mouseState.Y))
            {
                mouseIn = true;
                editBackButton.isSelected = true;
            }
            else
            {
                editBackButton.isSelected = false;
            }

            if (mouseState.LeftButton == ButtonState.Pressed && mouseStatePrev.LeftButton == ButtonState.Released)
            {
                if (umouseIn)
                {
                    foreach (MenuButton mb in editMenuButtons)
                    {
                        if (mb == mouseInButton && mb.isSelected)
                        {
                            if ((int)mb.weapon != -1
                                && (EquipmentLibrary.getWeapon(mb.weapon).value <= pointsFree + EquipmentLibrary.getWeapon(editUnitButton.unit.weapon).value))
                                editUnitButton.unit.weapon = mb.weapon;
                            else if ((int)mb.ar != -1
                                && (EquipmentLibrary.getArmor(mb.ar).value <= pointsFree + EquipmentLibrary.getArmor(editUnitButton.unit.ar).value))
                                editUnitButton.unit.ar = mb.ar;
                            else if ((int)mb.item != -1
                                && (EquipmentLibrary.getItem(mb.item).value <= pointsFree + EquipmentLibrary.getItem(editUnitButton.unit.item).value))
                                editUnitButton.unit.item = mb.item;
                            else if (mb.ability != -1)
                            {
                                if (editUnitButton.unit.abilities.Contains(mb.ability))
                                    editUnitButton.unit.abilities.Remove(mb.ability);
                                else if (editUnitButton.unit.abilities.Count < 3 && Ability.AbilityList[mb.ability].value <= pointsFree)
                                    editUnitButton.unit.abilities.Add(mb.ability);
                            }
                        }

                        mb.isSelected = false;
                    }

                    currentUpButton = mouseInButton;
                    currentUpButton.isSelected = true;
                }
                else if (mouseIn)
                {
                    ActivateButton(editBackButton);
                }

                pointsFree = MAX_POINTS - EquipmentLibrary.getWeapon(editUnitButton.unit.weapon).value - EquipmentLibrary.getArmor(editUnitButton.unit.ar).value - EquipmentLibrary.getItem(editUnitButton.unit.item).value;
                foreach (int i in editUnitButton.unit.abilities)
                    pointsFree -= Ability.AbilityList[i].value;
            }
        }

        protected void UpdateMenu(List<MenuButton> list)
        {
            //Select buttons. Mouse overrides keyboard, can be switched around if people prefer
            if (keyState.IsKeyDown(Keys.Down) && !keyStatePrev.IsKeyDown(Keys.Down))
                currentButton = list[list.IndexOf(currentButton) + 1 == list.Count ? 0 : list.IndexOf(currentButton) + 1];
            else if (keyState.IsKeyDown(Keys.Up) && !keyStatePrev.IsKeyDown(Keys.Up))
                currentButton = list[list.IndexOf(currentButton) == 0 ? list.Count - 1 : list.IndexOf(currentButton) - 1];

            bool mouseIn, cmouseIn;
            mouseIn = cmouseIn = false;

            foreach (MenuButton mb in list)
            {
                mb.isSelected = false;
                if (mb.bounds.Contains(mouseState.X, mouseState.Y))
                {
                    currentButton = mb;
                    mouseIn = true;
                }
            }

            MenuButton mouseInButton = null;
            if (menuState == Menu.CustomMenu)
                foreach (MenuButton mb in customUnitButtons)
                    if (mb.bounds.Contains(mouseState.X, mouseState.Y))
                    {
                        cmouseIn = true;
                        mouseInButton = mb;
                    }

            currentButton.isSelected = true;

            //Check if buttons are pressed to navigate
            if ((keyState.IsKeyDown(Keys.Enter) && !keyStatePrev.IsKeyDown(Keys.Enter)))
            {
                ActivateButton(currentButton);
            }
            else if (mouseState.LeftButton == ButtonState.Pressed && mouseStatePrev.LeftButton == ButtonState.Released)
            {
                if (mouseIn)
                {
                    ActivateButton(currentButton);
                }
                else if (cmouseIn)
                {
                    foreach (MenuButton mb in customUnitButtons)
                        mb.isSelected = false;

                    currentUnitButton = mouseInButton;
                    currentUnitButton.isSelected = true;
                }
            }
        }

        //Select an action to take based on the button. Currently incomplete
        protected void ActivateButton(MenuButton mb)
        {
            switch (mb.action)
            {
                case MenuButton.ButtonAction.MainMenu:
                    if (menuState == Menu.CustomMenu)
                        saveUnitSet();

                    menuState = Menu.MainMenu;
                    break;
                case MenuButton.ButtonAction.FullScreen:
                    //graphics.PreferredBackBufferWidth = graphics.IsFullScreen ? Properties.Settings.Default.ResX : GraphicsDevice.DisplayMode.Width;
                    //graphics.PreferredBackBufferHeight = graphics.IsFullScreen ? Properties.Settings.Default.ResY : GraphicsDevice.DisplayMode.Height;
                    //This stuff is for changing resolution. Possibly readd later but too much work at the moment
                    graphics.ToggleFullScreen();
                    //graphics.ApplyChanges();
                    break;
                case MenuButton.ButtonAction.SettingsMenu:
                    menuState = Menu.SettingsMenu;
                    break;
                case MenuButton.ButtonAction.CustomMenu:
                    menuState = Menu.CustomMenu;
                    RefreshUnitList();
                    break;
                case MenuButton.ButtonAction.ActivateUnit:
                    if (currentUnitButton != null)
                        currentUnitButton.unit.isActive = !currentUnitButton.unit.isActive;
                    else
                        break;

                    if (currentUnitButton.unit.isActive)
                        currentPlayer.unitSpecs.Add(currentUnitButton.unit);
                    else if (currentPlayer.unitSpecs.Contains(currentUnitButton.unit))
                        currentPlayer.unitSpecs.Remove(currentUnitButton.unit);

                    break;
                case MenuButton.ButtonAction.EditUnit:
                    if (currentUnitButton != null)
                    {
                        editUnitButton = new MenuButton(currentUnitButton.unit, new Vector2(100, 100), genericTexture);
                        menuState = Menu.EditMenu;
                    }
                    break;
                case MenuButton.ButtonAction.AddUnit:
                    Unit.unitSpecs.Add(new UnitSpecs());
                    RefreshUnitList();
                    break;
                case MenuButton.ButtonAction.DupUnit:
                    if (currentUnitButton != null)
                    {
                        Unit.unitSpecs.Add(new UnitSpecs(currentUnitButton.unit));
                        RefreshUnitList();
                    }
                    break;
                case MenuButton.ButtonAction.RemUnit:
                    if (currentUnitButton != null)
                    {
                        Unit.unitSpecs.Remove(currentUnitButton.unit);
                        RefreshUnitList();
                    }
                    break;
                case MenuButton.ButtonAction.Play:
                    {
                        initGame();
                        if (!invalidUnits)
                            menuState = Menu.InGame;
                        break;
                    }

                case MenuButton.ButtonAction.HostGame:
                    if (Gamer.SignedInGamers.Count >= 1)
                        initializeHostGame();
                    break;


                case MenuButton.ButtonAction.joingame0:
                    joinNetworkGame(0);
                    break;
                case MenuButton.ButtonAction.joingame1:
                    joinNetworkGame(1);
                    break;
                case MenuButton.ButtonAction.joingame2:
                    joinNetworkGame(2);
                    break;
                case MenuButton.ButtonAction.NetworkMenu:
                    menuState = Menu.networkMenu;
                    break;

                case MenuButton.ButtonAction.Quit:
                    this.Exit();
                    break;
                case MenuButton.ButtonAction.spawnLightI:
                    SpawnUnit(currentPlayer.unitSpecs[0], currentPlayer, currentBuildingSelection);
                    break;
                case MenuButton.ButtonAction.spawnLightII:
                    SpawnUnit(currentPlayer.unitSpecs[1], currentPlayer, currentBuildingSelection);
                    break;
                case MenuButton.ButtonAction.spawnMedI:
                    SpawnUnit(currentPlayer.unitSpecs[2], currentPlayer, currentBuildingSelection);
                    break;
                case MenuButton.ButtonAction.spawnMedII:
                    SpawnUnit(currentPlayer.unitSpecs[3], currentPlayer, currentBuildingSelection);
                    break;
                case MenuButton.ButtonAction.spawnHeavyI:
                    SpawnUnit(currentPlayer.unitSpecs[4], currentPlayer, currentBuildingSelection);
                    break;
                case MenuButton.ButtonAction.spawnHeavyII:
                    SpawnUnit(currentPlayer.unitSpecs[5], currentPlayer, currentBuildingSelection);
                    break;
                case MenuButton.ButtonAction.InitializeNetworkGame:
                    if (networkSession.IsHost)
                    {
                        InitializeNetworkGame();
                        initGame();
                    }
                    break;
                case MenuButton.ButtonAction.FindGame:
                    if (Gamer.SignedInGamers.Count >= 1)
                        menuState = Menu.joinNetworkMenu;
                    break;
            }
        }

        protected void initGame()
        {
            int lightCount, medCount, heavyCount;
            lightCount = medCount = heavyCount = 2;
            foreach (UnitSpecs us in currentPlayer.unitSpecs)
            {
                switch (us.type)
                {
                    case Unit.UnitType.Light:
                        lightCount--;
                        break;
                    case Unit.UnitType.Medium:
                        medCount--;
                        break;
                    case Unit.UnitType.Heavy:
                        heavyCount--;
                        break;
                }

            }

            foreach (Player p in players)
            {
                p.units.Clear();
                if (p.buildings.Count == 0)
                    p.buildings.Add(p.hq);
   
                p.buildings[0].currentHealth = p.buildings[0].maxHealth;
                p.requisition = Game1.currentMap.startingReq;
            }

            bullets.Clear();
            currentPlayer.unitSpecs.Sort();

            if (lightCount == 0 && medCount == 0 && heavyCount == 0)
            {
                Rectangle screen = GraphicsDevice.Viewport.Bounds;
                Rectangle bar = new Rectangle(screen.Left, screen.Bottom - BAR_SIZE, screen.Width, BAR_SIZE);

                buildingMenuButtons.Add(new MenuButton(currentPlayer.unitSpecs[0], MenuButton.ButtonAction.spawnLightI, (new Vector2(screen.Right - 2 * MenuButton.width - 20, bar.Top + 10)), buttonTexture));
                buildingMenuButtons.Add(new MenuButton(currentPlayer.unitSpecs[2], MenuButton.ButtonAction.spawnMedI, (new Vector2(screen.Right - 2 * MenuButton.width - 20, bar.Top + 70)), buttonTexture));
                buildingMenuButtons.Add(new MenuButton(currentPlayer.unitSpecs[4], MenuButton.ButtonAction.spawnHeavyI, (new Vector2(screen.Right - 2 * MenuButton.width - 20, bar.Top + 130)), buttonTexture));
                buildingMenuButtons.Add(new MenuButton(currentPlayer.unitSpecs[1], MenuButton.ButtonAction.spawnLightII, (new Vector2(screen.Right - 10 - MenuButton.width, bar.Top + 10)), buttonTexture));
                buildingMenuButtons.Add(new MenuButton(currentPlayer.unitSpecs[3], MenuButton.ButtonAction.spawnMedII, (new Vector2(screen.Right - 10 - MenuButton.width, bar.Top + 70)), buttonTexture));
                buildingMenuButtons.Add(new MenuButton(currentPlayer.unitSpecs[5], MenuButton.ButtonAction.spawnHeavyII, (new Vector2(screen.Right - 10 - MenuButton.width, bar.Top + 130)), buttonTexture));
                AINextUnit = currentPlayer.unitSpecs[0];
            }
            else
                invalidUnits = true;

            foreach (Terrain t in currentMap.SpriteTerrain)
            {
                if (!(t is Objectives))
                    continue;
                else
                    objectives.Add((Objectives)t);
            }
        }

        protected void SpawnUnit(UnitSpecs us, Player p, Building b)
        {
            Unit newUnit = (new Unit(us, b.spawnUnitAt(), p));
            if (newUnit.value > p.requisition)
                return;

            p.requisition -= newUnit.value;
            p.addUnit(newUnit);
        }

        protected void RefreshUnitList()
        {
            customUnitButtons.Clear();
            for (int i = 0; i < 3; i++)
                for (int u = i * 3; u < i * 3 + 3 && u < Unit.unitSpecs.Count; u++)
                    customUnitButtons.Add(new MenuButton(Unit.unitSpecs[u], new Vector2(120 + MenuButton.width + 260 * i, 200 + (100 + BUTTON_SPACING) * (u % 3)), genericTexture));

            currentUnitButton = null;

            invalidUnits = false;
        }

        protected void UpdateGame(GameTime gameTime)
        {
            //Check for EndGame Conditions. That is. Only 1 Player Controlls buildings
            int livingPlayers = 0;
            Player winningPlayer = null;
            foreach (Player p in players)
            {
                if (p.buildings.Count() > 0)
                {
                    livingPlayers++;
                    winningPlayer = p;
                }
            }
            if (livingPlayers == 0)
            {
                EndGameMessage = "The game is a Draw,";
                menuState = Menu.EndGame;
                return;
            }
            else if (livingPlayers == 1)
            {
                
                EndGameMessage = "Player: " + winningPlayer.id + " is the Victor.";
                menuState = Menu.EndGame;
                return;
            }

            if (networkSession != null)
            {
                 decodeState();
            }

            if (keyState.IsKeyDown(Keys.Escape))
            {
                menuState = Menu.PauseMenu;
                return;
            }


            //Input related stuff

            mouseCursor.Position = camera.ScreenToWorld(new Vector2(mouseState.X, mouseState.Y));

            //Forattack

            // Move the selected unit to the current mouse position when the left button is pressed
            if (mouseState.RightButton == ButtonState.Pressed && mouseStatePrev.RightButton == ButtonState.Released)
            {
                bool go = false;
                foreach (Player p in players)
                {
                    foreach (Unit u in p.units)
                    {
                        if (u.player.id != currentPlayer.id && u.Bounds.Contains((int)mouseCursor.Position.X, (int)mouseCursor.Position.Y))
                        {
                            go = true;
                            foreach (Unit x in currentSelection)
                            {
                                if (keyState.IsKeyDown(Keys.LeftShift))
                                {
                                    x.appendAttack(u);
                                }
                                else
                                {
                                    x.immediateAttack(u);
                                }

                            }
                        }
                    }

                    // building
                    if (go)
                    {
                        break;
                    }
                    foreach (Building b in p.buildings)
                    {
                        if (b.player.id != currentPlayer.id && b.hitBox.Contains((int)mouseCursor.Position.X, (int)mouseCursor.Position.Y))
                        {
                            go = true;
                            foreach (Unit x in currentSelection)
                            {
                                if (keyState.IsKeyDown(Keys.LeftShift))
                                {
                                    x.appendAttack(b);
                                }
                                else
                                {
                                    x.immediateAttack(b);
                                }
                            }
                        }
                    }


                    if (!go)
                        if (keyState.IsKeyDown(Keys.LeftShift))
                        {
                            foreach (Unit u in currentSelection)
                                u.appendWaypoint(mouseCursor.Position);
                        }
                        else
                        {
                            foreach (Unit u in currentSelection)
                                u.setWaypoint(mouseCursor.Position);
                        }
                }

            }

            //Move the camera if the mouse is at the edge of the screen
            if (mouseCursor.Position.X - 10 < camera.screenBounds.Left)
                camera.Move(new Vector2(-15, 0));

            if (mouseCursor.Position.X + 10 > camera.screenBounds.Right)
                camera.Move(new Vector2(15, 0));

            if (mouseCursor.Position.Y - 10 < camera.screenBounds.Top)
                camera.Move(new Vector2(0, -15));

            if (mouseCursor.Position.Y + 10 > camera.screenBounds.Bottom)
                camera.Move(new Vector2(0, 15));

            //Select units

            //Start creating a selection if the button has just been pressed
            if (mouseState.LeftButton == ButtonState.Pressed && mouseStatePrev.LeftButton == ButtonState.Released)
            {
                selectionBox = new Rectangle(mouseCursor.X, mouseCursor.Y, 0, 0);
                selectionCorner.X = mouseCursor.X;
                selectionCorner.Y = mouseCursor.Y;
            }

            //While the button is pressed, grow the selection
            if (mouseState.LeftButton == ButtonState.Pressed)
            {
                int rectX, rectY;

                rectX = (mouseCursor.X - selectionCorner.X < 0) ? mouseCursor.X : selectionCorner.X;
                rectY = (mouseCursor.Y - selectionCorner.Y < 0) ? mouseCursor.Y : selectionCorner.Y;
                selectionBox = new Rectangle(rectX, rectY, Math.Abs(mouseCursor.X - selectionCorner.X), Math.Abs(mouseCursor.Y - selectionCorner.Y));
            }



            if (mouseState.LeftButton == ButtonState.Released)
            {
                if (mouseStatePrev.LeftButton == ButtonState.Pressed)
                {
                    if (currentBuildingSelection != null)
                    {
                        bool buildingCall = false;
                        foreach (MenuButton mb in buildingMenuButtons)
                        {
                            mb.isSelected = false;
                            if (mb.bounds.Contains(mouseState.X, mouseState.Y))
                            {
                                currentButton = mb;
                                buildingCall = true;
                                //TODO
                                ActivateButton(mb);
                                break;
                            }
                        }
                        if (!buildingCall)
                        {
                            currentBuildingSelection.isSelected = false;
                            currentBuildingSelection = null;
                        }
                    }
                }

                // Move on to map
                if (mouseState.Y < GraphicsDevice.Viewport.Bounds.Bottom - BAR_SIZE)
                {
                    //If the button was just released, execute the selection
                    if (mouseStatePrev.LeftButton == ButtonState.Pressed)
                    {
                        currentEnemySelect = null;
                        if (keyState.IsKeyUp(Keys.LeftShift))
                            currentSelection.Clear();

                        foreach (Unit u in currentPlayer.units)
                        {
                            if (selectionBox.Intersects(u.Bounds))
                            {
                                currentSelection.Add(u);
                                u.isSelected = true;
                                currentEnemySelect = null;
                            }
                            else
                            {
                                u.isSelected = false;
                            }
                        }

                        if (currentSelection.Count == 0)                           
                            foreach (Building b in currentPlayer.buildings)
                            {
                                if (selectionBox.Intersects(b.hitBox))
                                {
                                    currentBuildingSelection = b;
                                    b.isSelected = true;
                                    currentEnemySelect = null;
                                }

                            }

                        if (currentBuildingSelection == null)
                            foreach (Player p in players)
                            {
                                if (p == currentPlayer)
                                    continue;

                                foreach (Unit u in p.units)
                                {
                                    
                                    if (selectionBox.Intersects(u.Bounds))
                                    {
                                        currentEnemySelect = u;
                                        break;
                                    }
                                    
                                }
                            }
                    }
                }
                
                //Reset the selection box
                selectionBox = new Rectangle(-1, -1, 0, 0);
            }

            if (keyState.IsKeyDown(Keys.D1))
                control(1);
            else if (keyState.IsKeyDown(Keys.D2))
                control(2);
            else if (keyState.IsKeyDown(Keys.D3))
                control(3);
            else if (keyState.IsKeyDown(Keys.D4))
                control(4);
            else if (keyState.IsKeyDown(Keys.D5))
                control(5);
            else if (keyState.IsKeyDown(Keys.D6))
                control(6);
            else if (keyState.IsKeyDown(Keys.D7))
                control(7);
            else if (keyState.IsKeyDown(Keys.D8))
                control(8);
            else if (keyState.IsKeyDown(Keys.D9))
                control(9);
            else if (keyState.IsKeyDown(Keys.D0))
                control(0);


            

            //Center the camera on the selected unit if Space is pressed
            if (keyState.IsKeyDown(Keys.Space))
                camera.LookAt(currentSelection[0]);

            foreach (Player p in players)
                p.Update(gameTime);

            List<Bullet> deadBullets = new List<Bullet>();
            foreach (Bullet b in bullets)
            {
                b.Update();
                if (b.killFlag)
                    deadBullets.Add(b);
            }

            foreach (Bullet b in deadBullets)
            {
                bullets.Remove(b);
            }


            if(AIMode)
                runAI(gameTime);

            //CurrentMap.update();
            currentMap.Update(gameTime);

            //
            if (networkSession != null && (updateSpan + lastEncode) < gameTime.TotalGameTime)
            {
                lastEncode = gameTime.TotalGameTime;
                
                if (networkSession.SessionState == NetworkSessionState.Playing)
                {
                    EncodePlayer(currentPlayer);

                    LocalNetworkGamer me = networkSession.LocalGamers[0];
                    if (packetWriter.Length > 0)
                    {
                        foreach (NetworkGamer ng in networkSession.AllGamers)
                        {
                            if (ng != me)
                                me.SendData(packetWriter, SendDataOptions.None, ng);
                        }
                    }
                }
            }




        } // END rungame

        protected void control(int index)
        {
            if (keyState.IsKeyDown(Keys.LeftControl))
            {
                ctrlGroups[index].Clear();
                ctrlGroups[index].AddRange(currentSelection);
            }
            else if (ctrlGroups[index].Count != 0)
            {
                foreach (Unit u in currentPlayer.units)
                {
                    if (ctrlGroups[index].Contains(u))
                        u.isSelected = true;
                    else
                        u.isSelected = false;
                }

                currentSelection.Clear();
                currentSelection.AddRange(ctrlGroups[index]);
            }
        }

        protected void runAI(GameTime gameTime)
        {
            if (AI.buildings.Count == 0 || currentPlayer.buildings.Count == 0)
                return;

            Random airand = new Random();
            

            if (AINextUnit.cost <= AI.requisition)
            {
                SpawnUnit(AINextUnit, AI, AI.buildings[0]);
                lastAISpawn = gameTime.TotalGameTime;
                AINextUnit = currentPlayer.unitSpecs[airand.Next(0, 5)];
            }
            else if (lastAISpawn + TimeSpan.FromSeconds(10) < gameTime.TotalGameTime)
                AINextUnit = currentPlayer.unitSpecs[airand.Next(0, 5)];

             
            HQBuilding enemyHQ;

            foreach (Unit u in AI.units)
            {
                if (currentPlayer.buildings[0] != null)
                {
                    enemyHQ = (HQBuilding)currentPlayer.buildings[0];
                    float xDistance = u.Position.X - enemyHQ.position.X;
                    float yDistance = u.Position.Y - enemyHQ.position.Y;
                    // pythagoras
                    if (400 * 400 > xDistance * xDistance + yDistance * yDistance)
                    {
                        u.immediateAttack(enemyHQ);
                        continue;
                    }
                }                  

                bool atObj = false;
                if (u.waypoints.Count == 0)
                {
                    bool inHQRange = false;

                    float xDistance = u.Position.X - AI.buildings[0].position.X;
                    float yDistance = u.Position.Y - AI.buildings[0].position.Y;
                    // pythagoras
                    if (400 * 400 > xDistance * xDistance + yDistance * yDistance)
                    {
                        inHQRange = true;
                    }

                    foreach (Objectives o in objectives)
                    {
                        if (u.Bounds.Intersects(o.territory) && !inHQRange)
                            atObj = true;
                    }

                    if (objectives.Count < 1)
                        break;

                    if (!atObj)
                    {
                        int objek;
                        if (objectives.Count > 1)
                            objek = airand.Next(0, objectives.Count);
                        else
                            objek = 0;

                        if (objek >= objectives.Count - 1)
                            objek = objectives.Count - 1;

                        u.setWaypoint(new Vector2(objectives[objek].X + objectives[objek].size * Map.cellSize, objectives[objek].Y + objectives[objek].size * Map.cellSize));
                    }
                    else
                        u.waypoints.Clear();
                }
                else
                {
                    foreach (Unit z in currentPlayer.units)
                    {
                        float xDistance = u.Position.X - z.Position.X;
                        float yDistance = u.Position.Y - z.Position.Y;
                        // pythagoras
                        if (400 * 400 > xDistance * xDistance + yDistance * yDistance)
                        {
                            u.immediateAttack(z);
                            continue;
                        }
                    }
                }
            }
        }
        #region En/Decode
        public void EncodePlayer(Player p)
        {
            //what is the playerDesignate?
            foreach (Unit u in p.units)
            {
                EncodeUnit(u);
            }
            foreach (Building b in p.buildings)
            {
                EncodeBuilding(b);
            }
            networkSession.Update();
        }

        public void EncodeUnit(Unit u)
        {
            //State its a unit
            packetWriter.Write(1);
            //What unit is this?
            packetWriter.Write(u.designate);

            //encode position, portrait, and unitType
            packetWriter.Write(u.Position);
            packetWriter.Write(u.classType);
            //Encode stats

            packetWriter.Write(u.maxHealth);
            packetWriter.Write(u.health);
            packetWriter.Write(u.atkPow);
            packetWriter.Write(u.armorPen);
            packetWriter.Write(u.moveSpeed);

            int i = u.waypoints.Count;

            if (i > 3)
            {
                i = 3;
            }

            //Tell how many waypoints to expect
            packetWriter.Write(i);

            
            //Encode 3 waypoints
            i = 0;
            while( i<  u.waypoints.Count && i < 3)
            {
                Object o = u.waypoints[i];
                if (i > 2)
                {
                    break;
                }
                if(o is Unit)
                {
                    //Tell it to expect a unit
                    packetWriter.Write(1);
                    packetWriter.Write(((Unit)o).unitDesignate);
                    
                }
                else if(o is Vector2)
                {
                    //Tell it to expect a vector
                    packetWriter.Write(2);
                    packetWriter.Write( ((Vector2) o) ) ;
                    
                }
                else if (o is Building)
                {
                    //Tell it to expect a building
                    packetWriter.Write(((Building)o).designate);
                    

                }
                i++;


            }
            
            //Should be everything for a unit. 

        }

        public void EncodeBuilding(Building b)
        {
                        //State its a Building
            packetWriter.Write(2);
            //Which building is this
            packetWriter.Write(b.designate);
            
            //encode position
            packetWriter.Write(b.X);
            packetWriter.Write(b.Y);

            //encode MaxHealth, currentHealth, armor
            packetWriter.Write(b.maxHealth);
            packetWriter.Write(b.currentHealth);
            packetWriter.Write(b.armor);
        }


        //FOR CLIENT use
        public void decodeState()
        {
            networkSession.Update();
            NetworkGamer sender;
            if (networkSession.LocalGamers.Count < 1)
            {
                return;
            }
            LocalNetworkGamer g = networkSession.LocalGamers[0];

            if (!g.IsDataAvailable)
            {
                return;
                //CRY
            }
            g.ReceiveData(packetReader, out sender);
            while (packetReader.Length > 0 && packetReader.Position < packetReader.Length)
            {

                if (!sender.IsLocal)
                {
                    switch (packetReader.ReadInt32())
                    {
                        case 1: //Its a unit call
                            {
                                #region unitDecode


                                //
                                int unitdesignate = packetReader.ReadInt32();

                                //check to see if this unit exists in our current state, if so. make they u, if not
                                int playerID = unitdesignate / 1000;
                                bool playerFound = false;
                                Unit u = null;
                                foreach (Player p in players)
                                {
                                    if (p.id == playerID)
                                    {
                                        playerFound = true;
                                        foreach (Unit pu in p.units)
                                        {
                                            if (pu.unitDesignate == unitdesignate)
                                            {
                                                u = pu;
                                                break;
                                            }
                                        }
                                        break;
                                    }
                                }
                                if (!playerFound)
                                {
                                    Player p = new Player();
                                    p.Initialize(playerID);
                                    players.Add(p);

                                }

                                if (u == null)
                                {
                                    u = new Unit();
                                    foreach (Player p in players)
                                    {
                                        if (p.id == playerID)
                                        {
                                            u.player = p;
                                            u.unitDesignate = unitdesignate;
                                            p.units.Add(u);
                                        }

                                    }
                                }


                                u.Position = packetReader.ReadVector2();
                                u.unitType = packetReader.ReadInt32();
                                u.maxHealth = packetReader.ReadInt32();
                                u.health = packetReader.ReadInt32();
                                u.atkPow = packetReader.ReadInt32();
                                u.armorPen = packetReader.ReadInt32();
                                u.moveSpeed = packetReader.ReadInt32();

                                u.remake();

                                //NOW DECODE WAYPOINTS! BWAHAHAH

                                int expectedWaypoints = packetReader.ReadInt32();

                                for (int i = 0; i < expectedWaypoints; i++)
                                {
                                    switch (packetReader.ReadInt32())
                                    {
                                        case 1:
                                            {
                                                int unitToAttack = packetReader.ReadInt32();
                                                int player = unitToAttack / 1000;
                                                foreach (Player p in players)
                                                    if (p.id == player)
                                                    {
                                                        foreach (Unit un in p.units)
                                                        {
                                                            if (un.designate == unitToAttack)
                                                            {
                                                                u.appendAttack(un);
                                                                break;
                                                            }
                                                        }
                                                        break;
                                                    }
                                            }
                                            break;
                                        case 2:
                                            {
                                                int buildingToAttack = packetReader.ReadInt32();
                                                int player = buildingToAttack / 100;
                                                foreach (Player p in players)
                                                    if (p.id == player)
                                                    {
                                                        foreach (Building b in p.buildings)
                                                        {
                                                            if (b.designate == buildingToAttack)
                                                            {
                                                                u.appendAttack(b);
                                                                break;
                                                            }
                                                        }
                                                        break;
                                                    }
                                            }
                                            break;
                                        case 3:
                                            {
                                                u.appendWaypoint(packetReader.ReadVector2());
                                            }
                                            break;
                                        default:
                                            break;
                                        //Not supposed to happen
                                    }


                                }
                            }
                                #endregion
                            break; //END UNIT DECODING
                        case 2: //Its a building
                            {
                                int Buildingdesignate = packetReader.ReadInt32();
                                //check to see if this unit exists in our current state, if so. make they u, if not
                                int playerID = Buildingdesignate / 100;
                                Building b = null;
                                foreach (Player p in players)
                                {
                                    if (p.id == playerID)
                                    {
                                        foreach (Building bu in p.buildings)
                                        {
                                            if (bu.designate == Buildingdesignate)
                                            {
                                                b = bu;
                                                //burn though position
                                                packetReader.ReadUInt32();
                                                packetReader.ReadUInt32();
                                                b.maxHealth = packetReader.ReadInt32();
                                                b.currentHealth = packetReader.ReadInt32();
                                                b.armor = packetReader.ReadInt32();
                                                break;
                                            }
                                        }
                                        break;
                                    }
                                }

                                if (b == null)
                                {
                                    foreach (Player p in players)
                                    {
                                        if (p.id == playerID)
                                        {
                                            b = new Building(packetReader.ReadInt32(), packetReader.ReadInt32(), 4 * Map.cellSize, 4 * Map.cellSize, HQ, p);

                                            p.buildings.Add(b);

                                        }
                                    }
                                }
                            }
                            break;


                        default:
                            break;
                        //this shouldent happen
                    }
               }
                
            }
            //TODO
        }
        #endregion



        #endregion

        #region Draw

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            switch (menuState)
            {
                case Menu.MainMenu:
                    DrawMainMenu();
                    break;
                case Menu.CustomMenu:
                    DrawCustomMenu();
                    break;
                case Menu.EditMenu:
                    DrawEditMenu();
                    break;
                case Menu.SettingsMenu:
                    DrawSettingsMenu();
                    break;
                case Menu.InGame:
                    DrawGame();
                    break;
                case Menu.PauseMenu:
                    DrawPauseMenu();
                    break;
                case Menu.EndGame:
                    DrawEndGame();
                    break;
                case Menu.networkMenu:
                    DrawNetworkMenu();
                    break;
                case Menu.hostLobby:
                    DrawHostLobby();
                    break;
                case Menu.joinNetworkMenu:
                    DrawJoinNetworkMenu();
                    break;
                default:
                    Console.WriteLine("Error");
                    break;
            }

            spriteBatch.Begin();
            spriteBatch.Draw(cursorTexture, new Vector2(Mouse.GetState().X, Mouse.GetState().Y), Color.White); //Cursor
            spriteBatch.End();

            base.Draw(gameTime);
        }

        protected void DrawHostLobby()
        {
            spriteBatch.Begin();
            spriteBatch.Draw(titleScreen, GraphicsDevice.Viewport.Bounds, Color.White);
            foreach (MenuButton mb in hostLobbyButtons)
            {
                if (networkSession == null || networkSession.AllGamers.Count < 2)
                {
                    mb.Draw(spriteBatch);
                    messageButton.title = "Waiting for more Players to join";
                    messageButton.Draw(spriteBatch);
                    break;
                }
                else
                {
                    mb.Draw(spriteBatch);
                }

            }

            spriteBatch.End();
        }

        protected void DrawSettingsMenu()
        {
            spriteBatch.Begin();
            Vector2 center = new Vector2(GraphicsDevice.Viewport.Width / 2, 50);
            


            spriteBatch.Draw(screenBG, GraphicsDevice.Viewport.Bounds, Color.White);
            foreach (MenuButton mb in settingsMenuButtons)
                mb.Draw(spriteBatch);

            DrawCenteredString("Credits", center, spriteBatch, Color.Blue);
            //\n\nIron Winter was created by:\nSam Chase\nAlex Hanemann\nCole Mercer\n\nWith art by:\nRebecca Hanson\nLaDonna Rios\n\nSpecial thanks to:\nProf Andrew Nuxoll"
            DrawCenteredString("Created by:", new Vector2 (center.X,center.Y + 25 * 2), spriteBatch,Color.Blue);
            DrawCenteredString("Sam Chase", new Vector2 (center.X,center.Y + 25 * 3), spriteBatch, Color.Black);
            DrawCenteredString("Alex Hanemann", new Vector2(center.X, center.Y + 25 * 4), spriteBatch, Color.Black);
            DrawCenteredString("Cole Mercer", new Vector2(center.X, center.Y + 25 * 5), spriteBatch, Color.Black);
            DrawCenteredString("With art by:", new Vector2(center.X, center.Y + 25 * 7), spriteBatch, Color.Blue);
            DrawCenteredString("LaDonna Rios", new Vector2(center.X, center.Y + 25 * 8), spriteBatch, Color.Black);
            DrawCenteredString("Rebecca Hanson", new Vector2(center.X, center.Y + 25 * 9), spriteBatch, Color.Black);
            DrawCenteredString("Special thanks to:", new Vector2(center.X, center.Y + 25 * 11), spriteBatch, Color.Blue);
            DrawCenteredString("Prof Andrew Nuxoll", new Vector2(center.X, center.Y + 25 * 12), spriteBatch, Color.Black);

            spriteBatch.End();
        }

        protected void DrawEndGame()
        {
            spriteBatch.Begin();

            spriteBatch.DrawString(font, EndGameMessage, new Vector2(300, 300), Color.Red);

            spriteBatch.Draw(genericTexture, new Rectangle(GraphicsDevice.Viewport.Width / 2 - 150, GraphicsDevice.Viewport.Height / 2 - 250, 300, 250), Color.Black);

            foreach (MenuButton mb in pauseMenuButtons)
            {
                mb.Draw(spriteBatch);
                break;
            }

            spriteBatch.End();

        }

        protected void DrawEditMenu()
        {
            spriteBatch.Begin();
            spriteBatch.Draw(screenBG, GraphicsDevice.Viewport.Bounds, Color.White);
            

            foreach (MenuButton mb in editMenuButtons)
            {
                if (editUnitButton.unit.weapon == mb.weapon || editUnitButton.unit.ar == mb.ar || editUnitButton.unit.item == mb.item
                    || editUnitButton.unit.abilities.Contains(mb.ability))
                    spriteBatch.Draw(genericTexture, new Rectangle(mb.bounds.X - 10, mb.bounds.Y - 10, mb.bounds.Width + 20, mb.bounds.Height + 20), Color.Green);

                mb.Draw(spriteBatch);
            }
            editUnitButton.Draw(spriteBatch);

            Rectangle unitBox = new Rectangle(editUnitButton.bounds.X + editUnitButton.bounds.Width + 50, editUnitButton.bounds.Y, 400, editUnitButton.bounds.Height);
            spriteBatch.Draw(genericTexture, unitBox, Color.Gray);

            spriteBatch.DrawString(MenuButton.menuFont, "Points Remaining: " + pointsFree, new Vector2(unitBox.Right - MenuButton.menuFont.MeasureString("Points Remaining: " + pointsFree).X - 10, unitBox.Y + 10), Color.Red);
            Unit test = new Unit(editUnitButton.unit, Vector2.Zero, currentPlayer);

            spriteBatch.DrawString(MenuButton.menuFont, test.name, new Vector2(unitBox.X + 10, unitBox.Y + 10), Color.Red);
            spriteBatch.DrawString(MenuButton.menuFont, "Health : " + test.maxHealth, new Vector2(unitBox.X + 10, unitBox.Y + 30), Color.Red);
            spriteBatch.DrawString(MenuButton.menuFont, "Armor : " + test.armor, new Vector2(unitBox.X + 10, unitBox.Y + 30 + 20), Color.Red);
            spriteBatch.DrawString(MenuButton.menuFont, "Speed : " + test.moveSpeed, new Vector2(unitBox.X + 10, unitBox.Y + 30 + 40), Color.Red);

            spriteBatch.DrawString(MenuButton.menuFont, "Damage : " + test.atkPow, new Vector2(unitBox.X + 10 + 100, unitBox.Y + 30), Color.Red);
        
           

            Rectangle statBox = new Rectangle(editUnitButton.bounds.X + editUnitButton.bounds.Width + 50 + 400 + 10, editUnitButton.bounds.Y, 400, editUnitButton.bounds.Height);
            spriteBatch.Draw(genericTexture, statBox, Color.Gray);

            if (currentUpButton != null)
            {
                Equipment dispEq = null;
                Ability dispAb = null;

                if ((int)currentUpButton.ar != -1)
                    dispEq = EquipmentLibrary.getArmor(currentUpButton.ar);
                else if ((int)currentUpButton.weapon != -1)
                    dispEq = EquipmentLibrary.getWeapon(currentUpButton.weapon);
                else if ((int)currentUpButton.item != -1)
                    dispEq = EquipmentLibrary.getItem(currentUpButton.item);
                else if (currentUpButton.ability != -1)
                    dispAb = Ability.AbilityList[currentUpButton.ability];

                if (dispEq != null)
                {
                    dispEq.Display(spriteBatch, new Rectangle(statBox.X + 10, statBox.Y + 10, Ability.DISPLAY_SIZE, Ability.DISPLAY_SIZE));
                    spriteBatch.DrawString(MenuButton.menuFont, dispEq.name, new Vector2(statBox.X + Ability.DISPLAY_SIZE + 20, statBox.Y + 10), Color.Red);
                    spriteBatch.DrawString(MenuButton.menuFont, "Health : " + dispEq.maxHealth, new Vector2(statBox.X + Ability.DISPLAY_SIZE + 20, statBox.Y + 30), Color.Red);
                    spriteBatch.DrawString(MenuButton.menuFont, "Armor : " + dispEq.armor, new Vector2(statBox.X + Ability.DISPLAY_SIZE + 20, statBox.Y + 30 + 20), Color.Red);
                    spriteBatch.DrawString(MenuButton.menuFont, "Speed : " + dispEq.moveSpeed, new Vector2(statBox.X + Ability.DISPLAY_SIZE + 20, statBox.Y + 30 + 40), Color.Red);
                    spriteBatch.DrawString(MenuButton.menuFont, "Cost : " + dispEq.value, new Vector2(statBox.Right - MenuButton.menuFont.MeasureString("Cost : " + dispEq.value).X - 10, statBox.Y + 10), Color.Red);

                    spriteBatch.DrawString(MenuButton.menuFont, "Damage : " + dispEq.atkPow, new Vector2(statBox.X + Ability.DISPLAY_SIZE + 20 + 100, statBox.Y + 30), Color.Red);
                    spriteBatch.DrawString(MenuButton.menuFont, "ArPen : " + dispEq.armorPen, new Vector2(statBox.X + Ability.DISPLAY_SIZE + 20 + 100, statBox.Y + 30 + 20), Color.Red);
                    //spriteBatch.DrawString(MenuButton.menuFont, "Attack Move? : " + dispEq.canMoveWhileAttacking, new Vector2(statBox.X + Ability.DISPLAY_SIZE + 20 + 100, statBox.Y + 30 + 40), Color.Red);
                }
                else if (dispAb != null)
                {
                    dispAb.Display(spriteBatch, new Rectangle(statBox.X + 10, statBox.Y + 10, Ability.DISPLAY_SIZE, Ability.DISPLAY_SIZE));
                    spriteBatch.DrawString(MenuButton.menuFont, dispAb.name, new Vector2(statBox.X + Ability.DISPLAY_SIZE + 20, statBox.Y + 10), Color.Red);
                    spriteBatch.DrawString(MenuButton.menuFont, dispAb.displayText, new Vector2(statBox.X + Ability.DISPLAY_SIZE + 20, statBox.Y + 30), Color.Red);
                    spriteBatch.DrawString(MenuButton.menuFont, "Cost : " + dispAb.value, new Vector2(statBox.Right - MenuButton.menuFont.MeasureString("Cost : " + dispAb.value).X - 10, statBox.Y + 10), Color.Red);

                    spriteBatch.DrawString(MenuButton.menuFont, "Damage : " + dispAb.atkPow, new Vector2(statBox.X + Ability.DISPLAY_SIZE + 20, statBox.Y + 70), Color.Red);
                    spriteBatch.DrawString(MenuButton.menuFont, "ArPen : " + dispAb.armorPen, new Vector2(statBox.X + Ability.DISPLAY_SIZE + 20 + 100, statBox.Y + 70), Color.Red);

                }
            }

            editBackButton.Draw(spriteBatch);

            spriteBatch.End();
        }

        protected void DrawCenteredString(string message, Vector2 position, SpriteBatch spriteBatch, Color color)
        {
            Vector2 origin = MenuButton.menuFont.MeasureString(message) / 2;
            spriteBatch.DrawString(MenuButton.menuFont, message, position + Vector2.One, Color.White, 0f, origin, 1f, SpriteEffects.None, 0f);
            spriteBatch.DrawString(MenuButton.menuFont, message, position + new Vector2(-1, -1), Color.White, 0f, origin, 1f, SpriteEffects.None, 0f);
            spriteBatch.DrawString(MenuButton.menuFont, message, position + new Vector2(-1, 1), Color.White, 0f, origin, 1f, SpriteEffects.None, 0f);
            spriteBatch.DrawString(MenuButton.menuFont, message, position + new Vector2(1, -1), Color.White, 0f, origin, 1f, SpriteEffects.None, 0f);

            spriteBatch.DrawString(MenuButton.menuFont, message, position, color, 0f, origin, 1f, SpriteEffects.None, 1f);
        }

        protected void DrawMainMenu()
        {         
            spriteBatch.Begin();
            spriteBatch.Draw(titleScreen, GraphicsDevice.Viewport.Bounds, Color.White);
            if (invalidUnits)
                spriteBatch.DrawString(MenuButton.menuFont, "Invalid unit composition", new Vector2(GraphicsDevice.Viewport.Width / 2 - MenuButton.menuFont.MeasureString("Invalid unit composition").X / 2, GraphicsDevice.Viewport.Height / 2 - 50), Color.Red);
            foreach (MenuButton mb in mainMenuButtons)
                mb.Draw(spriteBatch);
            spriteBatch.End();
        }

        protected void DrawNetworkMenu()
        {
            spriteBatch.Begin();
            spriteBatch.Draw(screenBG, GraphicsDevice.Viewport.Bounds, Color.White);

            if (Gamer.SignedInGamers.Count < 1)
                spriteBatch.DrawString(MenuButton.menuFont, "No signed in profile, press Home to sign in", new Vector2(GraphicsDevice.Viewport.Width / 2 - MenuButton.menuFont.MeasureString("No signed in profile, press Home to sign in").X / 2, GraphicsDevice.Viewport.Height / 2 - 50), Color.Red);

            

            foreach (MenuButton mb in networkMenuButtons)
            {
                mb.Draw(spriteBatch);
                if (Gamer.SignedInGamers.Count < 1)
                    break;
            }
            spriteBatch.End();
        }

        //Returns true once a valid local profile has been created
        protected void assureAccount()
        {
            
            Guide.ShowSignIn(1, false);
        }


        protected void DrawJoinNetworkMenu() //TODO
        {
            if (count == 500)
            {
                count = 0;
            }
            if (count == 0)
            {
                availableSessions = null;
                availableSessions = NetworkSession.Find(NetworkSessionType.SystemLink, 1, null);//Only update this once in a while. 
            }
            count++;

            int foundSessions = 0;
            foreach (AvailableNetworkSession availableSession in availableSessions)
            {
                // Create menu entries for each available session.
                
                joinNetworkButtons[foundSessions].title = availableSession.HostGamertag;

                foundSessions++;


                // Matchmaking can return up to 25 available sessions at a time, but
                // we don't have room to fit that many on the screen. In a perfect
                // world we should make the menu scroll if there are too many, but it
                // is easier to just not bother displaying more than we have room for.
                if (foundSessions >= joinNetworkButtons.Count - 1) //Minus one for the back button
                    break;
            }
            spriteBatch.Begin();
            spriteBatch.Draw(titleScreen, GraphicsDevice.Viewport.Bounds, Color.White);
            foreach (MenuButton mb in joinNetworkButtons)
            {
                if (mb.action == MenuButton.ButtonAction.MainMenu || (mb.action != MenuButton.ButtonAction.MainMenu && mb.title != null))
                {
                    mb.Draw(spriteBatch);
                }
            }
            spriteBatch.End();
        }


        protected void DrawCustomMenu()
        {
            GraphicsDevice.Clear(Color.Black);

            spriteBatch.Begin();
            spriteBatch.Draw(screenBG, GraphicsDevice.Viewport.Bounds, Color.White);
            //spriteBatch.DrawString(MenuButton.menuFont, "Customization", new Vector2(GraphicsDevice.Viewport.Width / 2 - MenuButton.menuFont.MeasureString("Customization").X / 2, 100), Color.Gray);

            Rectangle specBox = new Rectangle(100, GraphicsDevice.Viewport.Bounds.Bottom - 300, 125, 100);
            spriteBatch.Draw(genericTexture, specBox, Color.Gray);

            int lightCount, medCount, heavyCount;
            lightCount = medCount = heavyCount = 0;
            foreach (UnitSpecs us in currentPlayer.unitSpecs)
            {
                switch (us.type)
                {
                    case Unit.UnitType.Light:
                        lightCount++;
                        break;
                    case Unit.UnitType.Medium:
                        medCount++;
                        break;
                    case Unit.UnitType.Heavy:
                        heavyCount++;
                        break;
                }
            }

            spriteBatch.DrawString(MenuButton.menuFont, "Light : " + lightCount + "/2", new Vector2(specBox.Left + 10, specBox.Top + 10), Color.Red);
            spriteBatch.DrawString(MenuButton.menuFont, "Medium : " + medCount + "/2", new Vector2(specBox.Left + 10, specBox.Top + 35), Color.Red);
            spriteBatch.DrawString(MenuButton.menuFont, "Heavy : " + heavyCount + "/2", new Vector2(specBox.Left + 10, specBox.Top + 60), Color.Red);
            foreach (MenuButton mb in customMenuButtons)
                mb.Draw(spriteBatch);

            foreach (MenuButton mb in customUnitButtons)
                mb.Draw(spriteBatch);

            spriteBatch.End();
        }

        protected void DrawPauseMenu()
        {
            DrawGame();

            spriteBatch.Begin();

            spriteBatch.Draw(genericTexture, new Rectangle(GraphicsDevice.Viewport.Width / 2 - 150, GraphicsDevice.Viewport.Height / 2 - 250, 300, 250), Color.Black);

            foreach (MenuButton mb in pauseMenuButtons)
                mb.Draw(spriteBatch);

            spriteBatch.End();

        }

        protected void DrawGame()
        {
            GraphicsDevice.Clear(Color.SaddleBrown);

            //Draw the game field, translated according to the camera location
            spriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, camera.GetViewMatrix());

            spriteBatch.Draw(background, new Rectangle(0, 0, currentMap.lvlHeight * Map.cellSize * 2, currentMap.lvlWidth * Map.cellSize * 2), Color.White);

            //BACKGROUDN TODO



            currentMap.draw(spriteBatch);

            foreach (Player p in players)
            {               
                p.draw(spriteBatch);
                
            }

            foreach (Bullet b in bullets)
                b.Draw(spriteBatch);

            currentMap.draw(spriteBatch);

            spriteBatch.Draw(genericTexture, selectionBox, new Color(20, 10, 100, 70)); //Selection box

            spriteBatch.End();

            //Draw UI elements at literal screen locations
            spriteBatch.Begin();
            spriteBatch.DrawString(font, "Requisition: " + currentPlayer.requisition, new Vector2(20, 20), Color.DarkTurquoise);

            DrawBottomBar(spriteBatch);
            spriteBatch.End();
        }

        //Draw the bottom bar, with selection details and map
        protected void DrawBottomBar(SpriteBatch sb)
        {
            Rectangle screen = GraphicsDevice.Viewport.Bounds;
            Rectangle bar = new Rectangle(screen.Left, screen.Bottom - BAR_SIZE, screen.Width, BAR_SIZE);

            sb.Draw(genericTexture, bar, Color.Black);

            //Display selection bg
            sb.Draw(logoBar, new Rectangle(screen.Left + 20 + MAP_SIZE, bar.Top + 10, SELECTION_SIZE, BAR_SIZE - 20), Color.Gray);

            //Display stats bg
            Rectangle statBox = new Rectangle(screen.Left + 20 + MAP_SIZE + SELECTION_SIZE + 10, bar.Top + 10, SELECTION_SIZE - 295, BAR_SIZE - 20);

            //Display unit stats

            Unit currentDisplay = null;
            if (currentSelection.Count > 0)
                currentDisplay = currentSelection[0];
            else if (currentEnemySelect != null)
                currentDisplay = currentEnemySelect;

            if (currentDisplay != null)
            {
                sb.Draw(genericTexture, statBox, Color.Gray);
                //Display abilities 
                if (!networkDown)
                    for (int i = 0; i < currentDisplay.abilities.Count; i++)
                        Ability.AbilityList[currentDisplay.abilities[i]].Display(sb, new Vector2(screen.Right - (Ability.DISPLAY_SIZE + 10) * 4 + (Ability.DISPLAY_SIZE + 10) * (i + 1), bar.Top + 30));

                //Display equipment
                EquipmentLibrary.getWeapon(currentDisplay.weapon).Display(sb, new Vector2(screen.Right - (Ability.DISPLAY_SIZE + 10) * 4 + (Ability.DISPLAY_SIZE + 10) * (1), bar.Top + 30 + Ability.DISPLAY_SIZE + 10));
                EquipmentLibrary.getArmor(currentDisplay.ar).Display(sb, new Vector2(screen.Right - (Ability.DISPLAY_SIZE + 10) * 4 + (Ability.DISPLAY_SIZE + 10) * (2), bar.Top + 30 + Ability.DISPLAY_SIZE + 10));
                EquipmentLibrary.getItem(currentDisplay.item).Display(sb, new Vector2(screen.Right - (Ability.DISPLAY_SIZE + 10) * 4 + (Ability.DISPLAY_SIZE + 10) * (3), bar.Top + 30 + Ability.DISPLAY_SIZE + 10));

                //Display stats
                spriteBatch.DrawString(MenuButton.menuFont, currentDisplay.name, new Vector2(statBox.X + 10, statBox.Y + 10), Color.Red);
                spriteBatch.DrawString(MenuButton.menuFont, "Health : " + currentDisplay.health, new Vector2(statBox.X + 10, statBox.Y + 30), Color.Red);
                spriteBatch.DrawString(MenuButton.menuFont, "Armor : " + currentDisplay.armor, new Vector2(statBox.X + 10, statBox.Y + 30 + 20), Color.Red);
                spriteBatch.DrawString(MenuButton.menuFont, "Speed : " + currentDisplay.moveSpeed, new Vector2(statBox.X + 10, statBox.Y + 30 + 40), Color.Red);

                spriteBatch.DrawString(MenuButton.menuFont, "Damage : " + currentDisplay.atkPow, new Vector2(statBox.X + 10, statBox.Y + 30 + 60), Color.Red);
                spriteBatch.DrawString(MenuButton.menuFont, "ArPen : " + currentDisplay.armorPen, new Vector2(statBox.X + 10, statBox.Y + 30 + 80), Color.Red);

                //Display portrait
                sb.Draw(Unit.Portraits[currentDisplay.portrait], new Rectangle(screen.Right - (Ability.DISPLAY_SIZE + 10) * 3 - Unit.PORTRAIT_WIDTH - 10, bar.Top + 10, 150, BAR_SIZE - 20), Color.White);
            }
            
            // TODO
            if (currentBuildingSelection != null)
            {
                foreach (MenuButton b in buildingMenuButtons)
                {
                    b.Draw(sb);
                }
            }


            //Display map
            Rectangle mapBox = new Rectangle(screen.Left + 5, bar.Top + 10, BAR_SIZE - 20, BAR_SIZE - 20);
            sb.Draw(genericTexture, mapBox , Color.Gray);

            Rectangle realMapBox = new Rectangle(mapBox.Left + 5, mapBox.Top + 5, mapBox.Width - 10, mapBox.Height - 10);
            sb.Draw(genericTexture, realMapBox, Color.SaddleBrown);

            int mapX, mapY;
            mapX = (mapBox.Width - 20) / currentMap.Terrain.GetLength(0);
            mapY = (mapBox.Height) / currentMap.Terrain.GetLength(0);

            foreach (Player p in players)
                foreach (Unit u in p.units)
                {
                    int X = (int)((u.X / ((float)currentMap.Terrain.GetLength(0) * Map.cellSize)) * (realMapBox.Width));
                    int Y = (int)((u.Y / ((float)currentMap.Terrain.GetLength(0) * Map.cellSize)) * (realMapBox.Width));
                    sb.Draw(genericTexture, new Rectangle(realMapBox.Left + X, realMapBox.Top + Y, mapX, mapY), u.isSelected ? Color.Green : p.color);
                }

            foreach (Terrain t in currentMap.SpriteTerrain)
            {
                if(t is Objectives || t is Building)
                {
                    Color color;
                    int size = t is HQBuilding ? 12 : 6;

                    if (t is Building)
                        color = ((Building)t).ctrlPlayer.color;
                    else
                        color = ((Objectives)t).controllingPlayer == null ? Color.White : ((Objectives)t).controllingPlayer.color;

                    //no idea why building and objective don't use the same variable
                    //they do inherit from the same place after all

                    float lodf = ((t.X / (currentMap.Terrain.GetLength(0) * Map.cellSize)));
                    int X = (int)((t.X / ((float)currentMap.Terrain.GetLength(0) * Map.cellSize)) * (realMapBox.Width));
                    int Y = (int)((t.Y / ((float)currentMap.Terrain.GetLength(0) * Map.cellSize)) * (realMapBox.Width));
                    sb.Draw(genericTexture, new Vector2(realMapBox.Left + X, realMapBox.Top + Y), null, color, 0f, Vector2.Zero, size, SpriteEffects.None, 0);
                }
            }

            for (int i = 0; i < currentMap.Terrain.GetLength(0); i++)
            {
                for (int u = 0; u < currentMap.Terrain.GetLength(1); u++)
                {
                    Color color = Color.SaddleBrown;
                    //draw terrain in here maybe
                    
                    //sb.Draw(genericTexture, new Rectangle(screen.Left + 5 + i * mapX, bar.Top + 10 + u * mapY, mapX, mapY), color);
                }
            }
        }


        #endregion

        #region Save/Load

        public void saveUnitSet()
        {
            FileStream fs = new FileStream("UnitConfiguration.dat", FileMode.Create);

            BinaryFormatter formatter = new BinaryFormatter();
            try
            {
                formatter.Serialize(fs, Unit.unitSpecs);
            }
            catch (SerializationException e)
            {
                Console.WriteLine("Failed to save unit specs. Reason: " + e.Message);
                throw;
            }
            finally
            {
                fs.Close();
            }
        }

        public void loadUnitSet()
        {
            if (File.Exists("UnitConfiguration.dat"))
            {
                FileStream fs = new FileStream("UnitConfiguration.dat", FileMode.Open);
                try
                {
                    BinaryFormatter formatter = new BinaryFormatter();
                    Unit.unitSpecs = (List<UnitSpecs>)formatter.Deserialize(fs);

                    if (Unit.unitSpecs.Count == 0)
                        ResetUnitSpecs();

                    foreach (UnitSpecs us in Unit.unitSpecs)
                        if (us.isActive)
                            currentPlayer.unitSpecs.Add(us);
                }
                catch (SerializationException e)
                {
                    Console.WriteLine("Failed to load unit specs. Reason: " + e.Message);
                    ResetUnitSpecs();
                }
                finally
                {
                    fs.Close();
                }
            }
            else
            {
                ResetUnitSpecs();
            }
        }

        protected void ResetUnitSpecs()
        {
            Unit.unitSpecs = new List<UnitSpecs>();
            for (int i = 0; i < 3; i++)
            {
                UnitSpecs us = new UnitSpecs();
                us.abilities = new List<int>();
                us.type = Unit.UnitType.Light;
                us.weapon = Weapon.types.pistol;
                us.ar = Armor.types.basic;
                us.item = Item.types.nan;
                us.name = "Light Unit " + (i + 1);
                us.isActive = false;
                Unit.unitSpecs.Add(us);
            }

            for (int i = 0; i < 3; i++)
            {
                UnitSpecs us = new UnitSpecs();
                us.abilities = new List<int>();
                us.type = Unit.UnitType.Medium;
                us.weapon = Weapon.types.pistol;
                us.ar = Armor.types.basic;
                us.item = Item.types.nan;
                us.name = "Medium Unit " + (i + 1);
                us.isActive = false;
                Unit.unitSpecs.Add(us);
            }

            for (int i = 0; i < 3; i++)
            {
                UnitSpecs us = new UnitSpecs();
                us.abilities = new List<int>();
                us.type = Unit.UnitType.Heavy;
                us.weapon = Weapon.types.pistol;
                us.ar = Armor.types.basic;
                us.item = Item.types.nan;
                us.name = "Heavy Unit " + (i + 1);
                us.isActive = false;
                Unit.unitSpecs.Add(us);
            }

        }
        #endregion
    }
}
